parameters:
  buildConfig: ''
  archType: ''
  osGroup: ''
  osSubgroup: ''
  container: ''
  testGroup: ''
  crossBuild: false
  readyToRun: false
  hotColdSplitting: false
  liveLibrariesBuildConfig: ''
  compositeBuildMode: false
  useCodeFlowEnforcement: ''
  helixQueues: ''
  condition: true
  displayNameArgs: ''
  runInUnloadableContext: false
  tieringTest: false
  runtimeVariant: ''
  variables: {}
  pool: ''
  runtimeFlavor: 'coreclr'
  shouldContinueOnError: false
  dependsOn: []
  SuperPmiCollect: false
  unifiedArtifactsName: ''
  unifiedBuildNameSuffix: ''
  unifiedBuildConfigOverride: ''

### Test run job

### Each test run job depends on a corresponding test build job with the same
### buildConfig and archType.

jobs:
- template: /eng/pipelines/common/templates/runtimes/xplat-job.yml
  parameters:
    buildConfig: ${{ parameters.buildConfig }}
    archType: ${{ parameters.archType }}
    osGroup: ${{ parameters.osGroup }}
    osSubgroup: ${{ parameters.osSubgroup }}
    container: ${{ parameters.container }}
    testGroup: ${{ parameters.testGroup }}
    crossBuild: ${{ parameters.crossBuild }}
    liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
    helixType: 'build/tests/'
    runtimeVariant: ${{ parameters.runtimeVariant }}
    pool: ${{ parameters.pool }}
    condition: and(succeeded(), ${{ parameters.condition }})

    # Test jobs should continue on error for internal builds
    ${{ if eq(variables['System.TeamProject'], 'internal') }}:
      continueOnError: true

    ${{ if ne(parameters.dependsOn[0], '') }}:
      dependsOn: ${{ parameters.dependsOn }}

    ${{ if eq(parameters.dependsOn[0], '') }}:
      dependsOn:
      - ${{ if in(parameters.testGroup, 'innerloop', 'clrinterpreter') }}:
        - '${{ parameters.runtimeFlavor }}_common_test_build_p0_AnyOS_AnyCPU_${{parameters.buildConfig }}'
      - ${{ if notIn(parameters.testGroup, 'innerloop', 'clrinterpreter') }}:
        - '${{ parameters.runtimeFlavor }}_common_test_build_p1_AnyOS_AnyCPU_${{parameters.buildConfig }}'
      - ${{ if ne(parameters.unifiedArtifactsName, '')}}:
        - 'build_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ coalesce(parameters.unifiedBuildConfigOverride, parameters.buildConfig) }}_${{ parameters.unifiedBuildNameSuffix }}'

    # Compute job name from template parameters
    ${{ if in(parameters.testGroup, 'innerloop', 'clrinterpreter') }}:
      name: 'run_test_p0_${{ parameters.runtimeFlavor }}${{ parameters.runtimeVariant }}_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}'
      displayName: '${{ parameters.runtimeFlavor }} ${{ parameters.runtimeVariant}} Pri0 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'
    ${{ if notIn(parameters.testGroup, 'innerloop', 'clrinterpreter') }}:
      name: 'run_test_p1_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}'
      displayName: '${{ parameters.runtimeFlavor }} ${{ parameters.runtimeVariant }} Pri1 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'

    variables:

    - name: osGroup
      value: ${{ parameters.osGroup }}
    - name: osSubgroup
      value: ${{ parameters.osSubgroup }}
    - name: archType
      value: ${{ parameters.archType }}

    - name: monoAotBuildshCommand
      value: ''

    - ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}:
      - name: monoAotBuildshCommand
        value: 'mono_aot'

    - ${{ if eq(parameters.runtimeVariant, 'llvmfullaot') }}:
      - name: monoAotBuildshCommand
        value: 'mono_fullaot'

    - name: codeFlowEnforcementArg
      value: ''

    - ${{ if ne(parameters.useCodeFlowEnforcement, '') }}:
      - name: codeFlowEnforcementArg
        value: '/p:UseCodeFlowEnforcement=${{ parameters.useCodeFlowEnforcement }}'

    - name: crossgenArg
      value: ''
    - name: LogNamePrefix
      value: TestRunLogs

    - ${{ if eq(parameters.readyToRun, true) }}:
      - name: crossgenArg
        value: 'crossgen2'
      - name: LogNamePrefix
        value: TestRunLogs_R2R_CG2
      - ${{ if eq(parameters.compositeBuildMode, true) }}:
        - name: crossgenArg
          value: 'composite'
        - name: LogNamePrefix
          value: TestRunLogs_R2R_CG2_Composite
      - ${{ if eq(parameters.hotColdSplitting, true) }}:
        - name: LogNamePrefix
          value: TestRunLogs_R2R_CG2_HotColdSplitting

    - name: testTreeFilterArg
      value: ''

    # Only build GCSimulator tests when the gc-simulator group is specified.
    - ${{ if eq(parameters.testGroup, 'gc-simulator') }}:
      - name: testTreeFilterArg
        value: 'tree GC/Scenarios/GCSimulator'

    - template: /eng/pipelines/common/templates/runtimes/native-test-assets-variables.yml
      parameters:
        runtimeFlavor: coreclr
        testGroup: ${{ parameters.testGroup }}
        liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}

    # Variables used for SuperPMI collection
    - ${{ if eq(parameters.SuperPmiCollect, true) }}:
      - MchFileTag: '${{ parameters.osGroup }}.${{ parameters.archType }}.${{ parameters.buildConfig }}'
      - name: CollectionType
        value: 'run'
      - name: CollectionName
        value: 'coreclr_tests'
      - template: /eng/pipelines/coreclr/templates/jit-python-variables.yml
        parameters:
          osGroup: ${{ parameters.osGroup }}
      - ${{ if eq(parameters.osGroup, 'windows') }}:
        - name: MchFilesLocation
          value: '$(Build.SourcesDirectory)\artifacts\helixresults\'
        - name: MergedMchFileLocation
          value: '$(Build.SourcesDirectory)\artifacts\spmi_collection\'
        - name: SpmiLogsLocation
          value: '$(Build.SourcesDirectory)\artifacts\spmi_logs\'
      - ${{ if ne(parameters.osGroup, 'windows') }}:
        - name: MchFilesLocation
          value: '$(Build.SourcesDirectory)/artifacts/helixresults/'
        - name: MergedMchFileLocation
          value: '$(Build.SourcesDirectory)/artifacts/spmi_collection/'
        - name: SpmiLogsLocation
          value: '$(Build.SourcesDirectory)/artifacts/spmi_logs/'

    - template: /eng/pipelines/common/templates/runtimes/test-variables.yml
      parameters:
        osGroup: ${{ parameters.osGroup }}
        osSubgroup: ${{ parameters.osSubgroup }}
        testGroup: ${{ parameters.testGroup }}
        readyToRun: ${{ parameters.readyToRun }}
        runtimeFlavor: ${{ parameters.runtimeFlavor }}
        runtimeVariant: ${{ parameters.runtimeVariant }}

    - ${{ if eq(parameters.compositeBuildMode, true) }}:
      - name: crossgenArg
        value: 'composite'

    - ${{ if eq(variables['System.TeamProject'], 'internal') }}:
      - group: DotNet-HelixApi-Access

    - ${{ parameters.variables }}

    # TODO: update these numbers as they were determined long ago
    ${{ if eq(parameters.testGroup, 'innerloop') }}:
      ${{ if eq(parameters.archType, 'arm64') }}:
        timeoutInMinutes: 300
      ${{ else }}:
        timeoutInMinutes: 200
    ${{ if in(parameters.testGroup, 'outerloop', 'jit-cfg') }}:
      timeoutInMinutes: 270
    ${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}:
      timeoutInMinutes: 480
    ${{ if in(parameters.testGroup, 'jitstress', 'jitstress-random', 'jitstress-isas-arm', 'jitstressregs-x86', 'jitstressregs', 'jitstress2-jitstressregs', 'gcstress0x3-gcstress0xc', 'ilasm') }}:
      timeoutInMinutes: 390
    ${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter', 'pgo', 'pgostress', 'jit-experimental') }}:
      timeoutInMinutes: 510
    ${{ if in(parameters.testGroup, 'jitstress-isas-x86', 'jitstress-isas-avx512') }}:
      timeoutInMinutes: 960

    steps:

    - template: /eng/pipelines/common/download-artifact-step.yml
      parameters:
        unpackFolder: $(Build.SourcesDirectory)/artifacts/bin
        artifactFileName: '${{ parameters.unifiedArtifactsName }}$(archiveExtension)'
        artifactName: '${{ parameters.unifiedArtifactsName }}'
        displayName: 'unified artifacts'

    # Download and unzip the Microsoft.NET.Sdk.IL package needed for traversing
    # ilproj test projects during copynativeonly.
    - template: /eng/pipelines/common/download-artifact-step.yml
      parameters:
        unpackFolder: '$(microsoftNetSdkIlFolderPath)'
        artifactFileName: '$(microsoftNetSdkIlArtifactName).tar.gz'
        artifactName: '$(microsoftNetSdkIlArtifactName)'
        displayName: 'Microsoft.NET.Sdk.IL package'

    # Download and unzip managed test artifacts
    - template: /eng/pipelines/common/download-artifact-step.yml
      parameters:
        unpackFolder: '$(managedTestArtifactRootFolderPath)'
        artifactFileName: '$(managedGenericTestArtifactName).tar.gz'
        artifactName: '$(managedGenericTestArtifactName)'
        displayName: 'generic managed test artifacts'

    # Download and unzip native test artifacts
    - template: /eng/pipelines/common/download-artifact-step.yml
      parameters:
        unpackFolder: '$(nativeTestArtifactRootFolderPath)'
        artifactFileName: '$(nativeTestArtifactName)$(archiveExtension)'
        artifactName: '$(nativeTestArtifactName)'
        displayName: 'native test artifacts'

    # Publish native test components to test output folder. Sadly we cannot do this
    # during product build (so that we could zip up the files in their final test location
    # and directly unzip them there after download). Unfortunately the logic to copy
    # the native artifacts to the final test folders is dependent on availability of the
    # managed test artifacts. This step also generates the final test execution scripts.
    - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) copynativeonly $(logRootNameArg)Native $(testTreeFilterArg) $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(priorityArg) $(librariesOverrideArg) $(codeFlowEnforcementArg)
      displayName: Copy native test components to test output folder


    # Generate test wrappers. This is the step that examines issues.targets to exclude tests.
    - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) buildtestwrappersonly $(logRootNameArg)Wrappers $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(librariesOverrideArg) $(runtimeVariantArg)
      displayName: Generate test wrappers


    # Compose the Core_Root folder containing all artifacts needed for running
    # CoreCLR tests. This step also compiles the framework using Crossgen2
    # in ReadyToRun jobs.
    - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) generatelayoutonly $(logRootNameArg)Layout $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(librariesOverrideArg) $(runtimeVariantArg)
      displayName: Generate CORE_ROOT

    # Build a Mono LLVM AOT cross-compiler for non-amd64 targets (in this case, just arm64)
    - ${{ if and(eq(parameters.runtimeFlavor, 'mono'), or(eq(parameters.runtimeVariant, 'llvmaot'), eq(parameters.runtimeVariant, 'llvmfullaot'))) }}:
      - ${{ if eq(parameters.archType, 'arm64') }}:
        - script: ./build.sh
                  -subset mono
                  -c $(buildConfigUpper)
                  -arch $(archType)
                  /p:BuildMonoAotCrossCompiler=true
                  /p:BuildMonoAotCrossCompilerOnly=true
                  /p:MonoLibClang="/usr/local/lib/libclang.so.16"
                  /p:MonoAOTEnableLLVM=true
          displayName: "Build Mono LLVM AOT cross compiler"

    - ${{ if and(eq(parameters.runtimeFlavor, 'mono'), or(eq(parameters.runtimeVariant, 'llvmaot'), eq(parameters.runtimeVariant, 'llvmfullaot'))) }}:
      - ${{ if eq(parameters.archType, 'x64') }}:
        - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot $(monoAotBuildshCommand) $(buildConfig) $(archType) $(runtimeVariantArg)
          displayName: "LLVM AOT compile CoreCLR tests"
      - ${{ if eq(parameters.archType, 'arm64') }}:
        - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot $(monoAotBuildshCommand) $(buildConfig) $(archType) cross $(runtimeVariantArg) -maxcpucount:2
          displayName: "LLVM AOT cross-compile CoreCLR tests"
          env:
            __MonoToolPrefix: aarch64-linux-gnu-

    # Send tests to Helix
    - template: /eng/pipelines/common/templates/runtimes/send-to-helix-step.yml
      parameters:
        displayName: Send tests to Helix
        buildConfig: $(buildConfigUpper)
        archType: ${{ parameters.archType }}
        osGroup: ${{ parameters.osGroup }}
        osSubgroup: ${{ parameters.osSubgroup}}
        runtimeFlavor: ${{ parameters.runtimeFlavor }}
        shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
        runtimeVariant: ${{ parameters.runtimeVariant }}
        SuperPmiCollect: ${{ parameters.SuperPmiCollect }}

        ${{ if eq(variables['System.TeamProject'], 'public') }}:
          creator: $(Build.DefinitionName)

        helixBuild: $(Build.BuildNumber)
        helixSource: $(_HelixSource)

        # REVIEW: not sure why "cli" is part of the names here. Leave it for the ones that already had it,
        # but don't add it to new ones.
        ${{ if eq(parameters.readyToRun, true) }}:
          helixType: 'test/functional/r2r/cli/'
        ${{ if ne(parameters.readyToRun, true) }}:
          helixType: 'test/functional/cli/'

        helixQueues: ${{ parameters.helixQueues }}

        # This tests whether an array is empty
        ${{ if eq(join('', parameters.helixQueues), '') }}:
          condition: false

        publishTestResults: true

        timeoutPerTestInMinutes: $(timeoutPerTestInMinutes)
        timeoutPerTestCollectionInMinutes: $(timeoutPerTestCollectionInMinutes)
        runCrossGen2: ${{ eq(parameters.readyToRun, true) }}
        compositeBuildMode: ${{ parameters.compositeBuildMode }}
        runInUnloadableContext: ${{ parameters.runInUnloadableContext }}
        tieringTest: ${{ parameters.tieringTest }}
        hotColdSplitting: ${{ parameters.hotColdSplitting }}

        ${{ if eq(variables['System.TeamProject'], 'internal') }}:
          # Access token variable for internal project from the
          # DotNet-HelixApi-Access variable group
          helixAccessToken: $(HelixApiAccessToken)

        helixProjectArguments: '$(Build.SourcesDirectory)/src/tests/Common/helixpublishwitharcade.proj'

        # helixpublishwitharcade.proj processes one scenario per parallel MSBuild invocation. Each invocation only
        # creates Helix work items and them waits for their completion on the remote Helix machines, so is not
        # computationally intensive. We want Helix to be provided with all the possible work items in up front,
        # so can do as much work in parallel as possible. Thus, increase the amount of allowed MSBuild parallelism
        # to at least the maximum number of scenarios to be processed in a testGroup.
        #
        # We only need to do this for a testGroup with more than one or two scenarios, though it isn't functionally
        # a problem to always do it. Thus, we only exempt this setting for a few cases.
        ${{ if notIn(parameters.testGroup, 'innerloop', 'outerloop', 'clrinterpreter', 'ilasm', 'gc-longrunning', 'gc-simulator', 'gc-standalone', 'gc-standalone-server') }}:
          msbuildParallelism: '/maxcpucount:55'

        ${{ if in(parameters.testGroup, 'innerloop', 'outerloop') }}:
          ${{ if eq(parameters.runtimeFlavor, 'mono') }}:
            # tiered compilation isn't done on mono yet
            scenarios:
            - normal
          ${{ elseif eq(variables['Build.Reason'], 'PullRequest') }}:
            scenarios:
            - no_tiered_compilation
          ${{ else }}:
            scenarios:
            - normal
            - no_tiered_compilation

        ${{ if in(parameters.testGroup, 'jitstress') }}:
          scenarios:
          - jitminopts
          - jitstress1
          - jitstress1_tiered
          - jitstress2
          - jitstress2_tiered
          - disabler2r
          - tailcallstress
        ${{ if in(parameters.testGroup, 'jitstress-random') }}:
          scenarios:
          - jitstress_random_1
          - jitstress_random_2
        ${{ if in(parameters.testGroup, 'jitstress-isas-arm') }}:
          scenarios:
          - jitstress_isas_incompletehwintrinsic
          - jitstress_isas_nohwintrinsic
          - jitstress_isas_nohwintrinsic_nosimd
          - jitstress_isas_nosimd
        ${{ if in(parameters.testGroup, 'jitstress-isas-x86') }}:
          scenarios:
          - jitstress_isas_incompletehwintrinsic
          - jitstress_isas_nohwintrinsic
          - jitstress_isas_nohwintrinsic_nosimd
          - jitstress_isas_nosimd
          - jitstress_isas_x86_evex
          - jitstress_isas_x86_noaes
          - jitstress_isas_x86_noavx
          - jitstress_isas_x86_noavx2
          - jitstress_isas_x86_noavx512
          - jitstress_isas_x86_nobmi1
          - jitstress_isas_x86_nobmi2
          - jitstress_isas_x86_nofma
          - jitstress_isas_x86_nohwintrinsic
          - jitstress_isas_x86_nolzcnt
          - jitstress_isas_x86_nopclmulqdq
          - jitstress_isas_x86_nopopcnt
          - jitstress_isas_x86_nosse
          - jitstress_isas_x86_nosse2
          - jitstress_isas_x86_nosse3
          - jitstress_isas_x86_nosse3_4
          - jitstress_isas_x86_nosse41
          - jitstress_isas_x86_nosse42
          - jitstress_isas_x86_nossse3
          - jitstress_isas_1_x86_noaes
          - jitstress_isas_1_x86_noavx
          - jitstress_isas_1_x86_noavx2
          - jitstress_isas_1_x86_noavx512
          - jitstress_isas_1_x86_nobmi1
          - jitstress_isas_1_x86_nobmi2
          - jitstress_isas_1_x86_nofma
          - jitstress_isas_1_x86_nohwintrinsic
          - jitstress_isas_1_x86_nolzcnt
          - jitstress_isas_1_x86_nopclmulqdq
          - jitstress_isas_1_x86_nopopcnt
          - jitstress_isas_1_x86_nosse
          - jitstress_isas_1_x86_nosse2
          - jitstress_isas_1_x86_nosse3
          - jitstress_isas_1_x86_nosse3_4
          - jitstress_isas_1_x86_nosse41
          - jitstress_isas_1_x86_nosse42
          - jitstress_isas_1_x86_nossse3
          - jitstress_isas_2_x86_noaes
          - jitstress_isas_2_x86_noavx
          - jitstress_isas_2_x86_noavx2
          - jitstress_isas_2_x86_noavx512
          - jitstress_isas_2_x86_nobmi1
          - jitstress_isas_2_x86_nobmi2
          - jitstress_isas_2_x86_nofma
          - jitstress_isas_2_x86_nohwintrinsic
          - jitstress_isas_2_x86_nolzcnt
          - jitstress_isas_2_x86_nopclmulqdq
          - jitstress_isas_2_x86_nopopcnt
          - jitstress_isas_2_x86_nosse
          - jitstress_isas_2_x86_nosse2
          - jitstress_isas_2_x86_nosse3
          - jitstress_isas_2_x86_nosse3_4
          - jitstress_isas_2_x86_nosse41
          - jitstress_isas_2_x86_nosse42
          - jitstress_isas_2_x86_nossse3
        ${{ if in(parameters.testGroup, 'jitstress-isas-avx512') }}:
          scenarios:
          - jitstress_isas_x86_evex
          - jitstress_isas_x86_noavx512
          - jitstressregs0x2000
        ${{ if in(parameters.testGroup, 'jitstressregs-x86') }}:
          scenarios:
          - jitstressregs1_x86_noavx
          - jitstressregs2_x86_noavx
          - jitstressregs3_x86_noavx
          - jitstressregs4_x86_noavx
          - jitstressregs8_x86_noavx
          - jitstressregs0x10_x86_noavx
          - jitstressregs0x80_x86_noavx
          - jitstressregs0x1000_x86_noavx
          - jitstressregs0x2000_x86_noavx
        ${{ if in(parameters.testGroup, 'jitstressregs' ) }}:
          scenarios:
          - jitstressregs1
          - jitstressregs2
          - jitstressregs3
          - jitstressregs4
          - jitstressregs8
          - jitstressregs0x10
          - jitstressregs0x80
          - jitstressregs0x1000
          - jitstressregs0x2000
        ${{ if in(parameters.testGroup, 'jitstress2-jitstressregs') }}:
          scenarios:
          - jitstress2_jitstressregs1
          - jitstress2_jitstressregs2
          - jitstress2_jitstressregs3
          - jitstress2_jitstressregs4
          - jitstress2_jitstressregs8
          - jitstress2_jitstressregs0x10
          - jitstress2_jitstressregs0x80
          - jitstress2_jitstressregs0x1000
          - jitstress2_jitstressregs0x2000
        ${{ if in(parameters.testGroup, 'gcstress0x3-gcstress0xc') }}:
          scenarios:
          - gcstress0x3
          - gcstress0xc
        ${{ if in(parameters.testGroup, 'gcstress-extra') }}:
          scenarios:
          - heapverify1
          - gcstress0xc_disabler2r
          - gcstress0xc_disabler2r_jitstress2
          - gcstress0xc_disabler2r_heapverify1
          - gcstress0xc_jitstress1
          - gcstress0xc_jitstress2
          - gcstress0xc_tailcallstress
          - gcstress0xc_jitminopts_heapverify1
        ${{ if in(parameters.testGroup, 'r2r-extra') }}:
          scenarios:
          - jitstress1
          - jitstress2
          - jitstress1_tiered
          - jitstress2_tiered
          - jitstressregs1
          - jitstressregs2
          - jitstressregs3
          - jitstressregs4
          - jitstressregs8
          - jitstressregs0x10
          - jitstressregs0x80
          - jitstressregs0x1000
          - jitstressregs0x2000
          - jitminopts
          - forcerelocs
          - gcstress0xc
        ${{ if in(parameters.testGroup, 'pgo') }}:
          scenarios:
          - defaultpgo
        ${{ if in(parameters.testGroup, 'pgostress') }}:
          # We run a limited number of scenarios on the win-arm64 queues as we hit frequent timeouts on those queues otherwise.
          # The loss of coverage is not critical as win-arm64 is practically equivalent to linux-arm64 to the JIT.
          ${{ if and(eq(parameters.osGroup, 'windows'), eq(parameters.archType, 'arm64')) }}:
            scenarios:
            - fullpgo
            - fullpgo_random_gdv_edge
          ${{ else }}:
            scenarios:
            - fullpgo
            - fullpgo_methodprofiling
            - fullpgo_random_gdv
            - fullpgo_random_gdv_methodprofiling_only
            - fullpgo_random_gdv_edge
            - fullpgo_methodprofiling_always_optimized
            - syntheticpgo
            - syntheticpgo_blend
        ${{ if in(parameters.testGroup, 'gc-longrunning') }}:
          longRunningGcTests: true
          scenarios:
          - normal
        ${{ if in(parameters.testGroup, 'gc-simulator') }}:
          gcSimulatorTests: true
          scenarios:
          - normal
        ${{ if in(parameters.testGroup, 'gc-standalone') }}:
          scenarios:
          - gcstandalone
        ${{ if in(parameters.testGroup, 'gc-standalone-server') }}:
          scenarios:
          - gcstandaloneserver
        ${{ if in(parameters.testGroup, 'jitelthookenabled') }}:
          scenarios:
          - jitelthookenabled
          - jitelthookenabled_tiered
        ${{ if in(parameters.testGroup, 'jit-experimental') }}:
          ${{ if and(eq(parameters.osGroup, 'windows'), eq(parameters.archType, 'arm64')) }}:
            scenarios:
            - jitosr_stress
            - jitpartialcompilation_pgo
          ${{ else }}:
            scenarios:
            - jitosr_stress
            - jitosr_stress_random
            - jit_stress_splitting
            - jitpartialcompilation
            - jitpartialcompilation_pgo
            - jitobjectstackallocation
            - jitphysicalpromotion_only
            - jitphysicalpromotion_full
            - jitrlcse
        ${{ if in(parameters.testGroup, 'jit-cfg') }}:
          scenarios:
          - jitcfg
          - jitcfg_dispatcher_always
          - jitcfg_dispatcher_never
          - jitcfg_gcstress0xc
        ${{ if in(parameters.testGroup, 'ilasm') }}:
          scenarios:
          - ilasmroundtrip
        ${{ if in(parameters.testGroup, 'clrinterpreter') }}:
          scenarios:
          - clrinterpreter

    # Publish Logs
    - task: PublishPipelineArtifact@1
      displayName: Publish Logs
      inputs:
        targetPath: $(Build.SourcesDirectory)/artifacts/log
        artifactName: '${{ parameters.runtimeFlavor }}_${{ parameters.runtimeVariant }}_$(LogNamePrefix)_Attempt$(System.JobAttempt)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}'
      continueOnError: true
      condition: always()

    ########################################################################################################
    #
    # Finalize SuperPMI collection: (1) merge all MCH files generated by all Helix jobs, (2) upload MCH file to Azure Storage, (3) upload log files
    # Note that all these steps are "condition: always()" because we want to upload as much of the collection
    # as possible, even if there were test failures.
    #
    ########################################################################################################

    - ${{ if eq(parameters.SuperPmiCollect, true) }}:

      # Create required directories for merged mch collection and superpmi logs
      - ${{ if ne(parameters.osGroup, 'windows') }}:
        - script: |
            mkdir -p $(MergedMchFileLocation)
            mkdir -p $(SpmiLogsLocation)
          displayName: Create SuperPMI directories
          condition: always()
      - ${{ if eq(parameters.osGroup, 'windows') }}:
        - script: |
            mkdir $(MergedMchFileLocation)
            mkdir $(SpmiLogsLocation)
          displayName: Create SuperPMI directories
          condition: always()

      - script: $(PythonSetupScript)
        displayName: Enable python venv

      - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi.py merge-mch -log_level DEBUG -pattern $(MchFilesLocation)$(CollectionName).$(CollectionType)*.mch -output_mch_path $(MergedMchFileLocation)$(CollectionName).$(CollectionType).$(MchFileTag).mch
        displayName: 'Merge $(CollectionName)-$(CollectionType) SuperPMI collections'
        condition: always()

      - template: /eng/pipelines/common/upload-artifact-step.yml
        parameters:
          rootFolder: $(MergedMchFileLocation)
          includeRootFolder: false
          archiveType: $(archiveType)
          tarCompression: $(tarCompression)
          archiveExtension: $(archiveExtension)
          artifactName: 'SuperPMI_Collection_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
          displayName: 'Upload artifacts SuperPMI $(CollectionName)-$(CollectionType) collection'
          condition: always()

      # Add authenticated pip feed
      - task: PipAuthenticate@1
        displayName: 'Pip Authenticate'
        inputs:
          artifactFeeds: public/dotnet-public-pypi
          onlyAddExtraIndex: false
        condition: always()

      # Ensure the Python azure-storage-blob package is installed before doing the upload.
      - script: $(PipScript) install --upgrade pip && $(PipScript) install azure.storage.blob==12.5.0 --force-reinstall
        displayName: Upgrade Pip to latest and install azure-storage-blob Python package
        condition: always()

      - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi.py upload -log_level DEBUG -arch $(archType) -build_type $(buildConfig) -mch_files $(MergedMchFileLocation)$(CollectionName).$(CollectionType).$(MchFileTag).mch -core_root $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).x64.$(buildConfigUpper)
        displayName: 'Upload SuperPMI $(CollectionName)-$(CollectionType) collection to Azure Storage'
        condition: always()
        env:
          CLRJIT_AZ_KEY: $(clrjit_key1) # secret key stored as variable in pipeline

      - task: CopyFiles@2
        displayName: Copying superpmi.log of all partitions
        inputs:
          sourceFolder: '$(MchFilesLocation)'
          contents: '**/$(CollectionName).$(CollectionType)*.log'
          targetFolder: '$(SpmiLogsLocation)'
        condition: always()

      - task: PublishPipelineArtifact@1
        displayName: Publish SuperPMI logs
        inputs:
          targetPath: $(SpmiLogsLocation)
          artifactName: 'SuperPMI_Logs_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
        condition: always()

    ########################################################################################################
    #
    # End of SuperPMI processing
    #
    ########################################################################################################
